package butines.game2.entity;

import butines.common.math.Vector2D;
import butines.game2.sterring.Steering;

public abstract class EntityMoving extends Entity {

    protected final Vector2D acceleration; 
    protected final Vector2D heading;
    protected final Vector2D velocity;
    protected final Vector2D side;

    protected float radius;
    protected float mass;
    protected float maxSpeed;
    protected float maxForce;
    protected float maxTurnRate;

    protected final Steering steering;
    
    public EntityMoving() {
        steering = new Steering(this);
        velocity = new Vector2D();
        heading = new Vector2D(0, -1).normalise();
        acceleration = new Vector2D();
        side = new Vector2D();
        side.x = -heading.y;
        side.y = heading.x;
    }

    public void applySteeringForce(Vector2D force) {
        
        acceleration.div(force, mass);
        
        // update the velocity
        velocity.add(acceleration);
        
        // make sure vehicle does not exceed maximum velocity
        Vector2D.truncate(velocity, maxSpeed);
        
        // update the position
        position.add(velocity);
        
    }
    
    public void applyBrakingForce(float rate) {
        velocity.mult(rate);
    }
    
    public boolean isAtPosition(Vector2D pos) {
        float tolerance = 3; 
        return Vector2D.distanceSq(position, pos) < tolerance * tolerance;
    }
    
    public boolean isSpeedMaxedOut() {
        return maxSpeed * maxSpeed >= velocity.lengthSq();
    }
    
    public boolean isFacing(Vector2D target) {
        Vector2D toTarget = new Vector2D();
        toTarget.sub(target, position);
        toTarget.normalise();

        //first determine the angle between the heading vector and the target
        double angle = heading.angle(toTarget);

        //return true if the player is facing the target
       return (angle < 0.00001);
    }

    public boolean rotateHeadingToFacePosition(Vector2D target) {
        Vector2D toTarget = new Vector2D();
        toTarget.sub(target, position);
        toTarget.normalise();

        // first determine the angle between the heading vector and the target
        double angle = heading.angle(toTarget);

        // return true if the player is facing the target
        if (angle < 0.00001) {
            return true;
        }

        // clamp the amount to turn to the max turn rate
        if (angle > maxTurnRate) {
            angle = maxTurnRate;
        }

        float cos = (float) Math.cos(angle * heading.sign(toTarget));
        float sin = (float) Math.sin(angle * heading.sign(toTarget));

        heading.rotate(cos, sin);
        velocity.rotate(cos, sin);

        // finally recreate m_vSide
        side.x = -heading.y;
        side.y = heading.x;

        return false;
    }
    
    /** GETTERS AND SETTERS *******************************************/
    public float getRadius() {
        return radius;
    }

    public void setRadius(float radius) {
        this.radius = radius;
    }
    
    public float getMass() {
        return mass;
    }

    public void setMass(float mass) {
        this.mass = mass;
    }

    public float getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(float maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public float getMaxForce() {
        return maxForce;
    }

    public void setMaxForce(float maxForce) {
        this.maxForce = maxForce;
    }

    public float getMaxTurnRate() {
        return maxTurnRate;
    }

    public void setMaxTurnRate(float maxTurnRate) {
        this.maxTurnRate = maxTurnRate;
    }

    public Vector2D getVelocity() {
        return velocity;
    }

    public Vector2D getSide() {
        return side;
    }

    public Steering getSteering() {
        return steering;
    }

    public Vector2D getHeading() {
        return heading;
    }

    
}
